#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
#include <cstring>
#include <unordered_set>
#include <unordered_map>
#include <list>

using namespace std;

// 936. 戳印序列
class Solution
{
public:
    vector<int> movesToStamp(string stamp, string target) 
    {
        int m = stamp.size(), n = target.size();
        vector<int> indegree(n - m + 1, m);
        vector<vector<int>> g(n);
        queue<int> q;
        for(int i = 0; i <= n - m; ++i)
        {
            // i 开头的 m 个字符
            for(int j = 0; j < m; ++j)
            {
                if(target[i + j] == stamp[j])
                {
                    if(--indegree[i] == 0) q.push(i);
                }
                else
                {
                    // from：错误的位置，to：i 开头的下标
                    g[i + j].push_back(i);
                }
            }
        }

        // 标记被取消错误的位置
        vector<bool> visited(n);
        vector<int> ret(n - m + 1);
        int cnt = 0;
        while(!q.empty())
        {
            int x = q.front();
            q.pop();
            ret[cnt++] = x;
            // x : 开头位置，取消 x, x + 1, x + 2 ... x + m - 1 等位置的错误
            for(int i = 0; i < m; ++i)
            {
                if(!visited[x + i])
                {
                    visited[x + i] = true; // 取消错误
                    for(int y : g[x + i])
                    {
                        if(--indegree[y] == 0)
                        {
                            q.push(y);
                        }
                    }
                }
            }
        }

        if(cnt != n - m + 1) return {};
        reverse(ret.begin(), ret.end());
        return ret;
    }
};

// 2290. 到达角落需要移除障碍物的最小数目
class Solution 
{
public:
    int minimumObstacles(vector<vector<int>>& grid) 
    {
        int m = grid.size(), n = grid[0].size();
        int dist[m][n];
        memset(dist, 0x3f, sizeof dist);
        
        int dx[4] = {0, 0, -1, 1};
        int dy[4] = {-1, 1, 0, 0}; 
        deque<pair<int, int>> q;
        q.emplace_front(0, 0);
        dist[0][0] = 0;
        while(!q.empty())
        {
            auto [x, y] = q.front();
            q.pop_front();
            if(x == m - 1 && y == n - 1) return dist[x][y];
            for(int k = 0; k < 4; ++k)
            {
                int nx = x + dx[k], ny = y + dy[k];
                if(nx >= 0 && nx < m && ny >= 0 && ny < n)
                {
                    int w = grid[nx][ny];
                    if(dist[nx][ny] > dist[x][y] + w)
                    {
                        dist[nx][ny] = dist[x][y] + w;
                        w == 0 ? q.emplace_front(nx, ny) : q.emplace_back(nx, ny);
                    }
                }
            }
        }    
        return -1;
    }
};

// 1368. 使网格图至少有一条有效路径的最小代价
class Solution 
{
public:
    int minCost(vector<vector<int>>& grid) 
    {
        // 右，左，下，上
        int move[5][2] = {{-1, -1}, {0, 1}, {0, -1}, {1, 0}, {-1, 0}};
        int m = grid.size(), n = grid[0].size();
        int dist[m][n];
        memset(dist, 0x3f, sizeof dist);
        
        deque<pair<int, int>> q;
        q.emplace_front(0, 0);
        dist[0][0] = 0;
        while(!q.empty())
        {
            auto [x, y] = q.front();
            q.pop_front();
            if(x == m - 1 && y == n - 1) return dist[x][y];
            for(int k = 1; k <= 4; ++k)
            {
                int nx = x + move[k][0], ny = y + move[k][1];
                if(nx >= 0 && nx < m && ny >= 0 && ny < n)
                {
                    // 方向相同，权值为 0
                    // 方向不同，权值为 1
                    int w = grid[x][y] == k ? 0 : 1;
                    if(dist[nx][ny] > dist[x][y] + w)
                    {
                        dist[nx][ny] = dist[x][y] + w;
                        w == 0 ? q.emplace_front(nx, ny) : q.emplace_back(nx, ny);
                    }
                }
            }
        }
        return -1;
    }
};

// 407. 接雨水 II
class Solution 
{
public:
    int trapRainWater(vector<vector<int>>& heightMap) 
    {
        int m = heightMap.size(), n = heightMap[0].size();
        if(m <= 2 || n <= 2) return 0;

        priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q;
        vector<vector<bool>> visited(m, vector<bool>(n));
        for(int i = 0; i < m; ++i)
        {
            for(int j = 0; j < n; ++j)
            {
                if(i == 0 || i == m - 1 || j == 0 || j == n - 1)
                {
                    q.emplace(heightMap[i][j], i * n + j);
                    visited[i][j] = true;
                }
            }
        }

        int ret = 0;
        int dx[4] = {0, 0, -1, 1};
        int dy[4] = {-1, 1, 0, 0};
        while(!q.empty())
        {
            auto [w, p] = q.top();
            q.pop();
            int x = p / n, y = p % n;
            ret += w - heightMap[x][y];
            for(int k = 0; k < 4; ++k)
            {
                int nx = x + dx[k], ny = y + dy[k];
                if(nx >= 0 && nx < m && ny >= 0 && ny < n && !visited[nx][ny])
                {
                    q.emplace(max(heightMap[nx][ny], w), nx * n + ny);
                    visited[nx][ny] = true;
                }
            }
        }
        return ret;
    }
};

class Solution 
{
private:
    list<string> path;
    unordered_set<string> dict;
    vector<vector<string>> ret;
    unordered_set<string> curLevel;
    unordered_set<string> nextLevel;
    unordered_map<string, vector<string>> g;

    // begin -> end，一层层 bfs 去建图
    // 找到 begin 到 end 的路径，则返回 true
    bool bfs(string& begin, string& end)
    {
        bool flag = false;
        curLevel.emplace(begin);
        while(!curLevel.empty())
        {
            for(auto& s : curLevel) dict.erase(s);
            for(auto& s : curLevel)
            {
                string tmp = s;
                // 每个位置，字符 a-z 都试一遍
                for(int i = 0; i < tmp.size(); ++i)
                {
                    char old = tmp[i];
                    for(char ch = 'a'; ch <= 'z'; ++ch)
                    {
                        if(ch != old)
                        {
                            tmp[i] = ch;
                            if(dict.count(tmp))
                            {
                                if(tmp == end) flag = true; // 找到 begin 到 end 的路径了
                                g[tmp].emplace_back(s); // 建反图
                                if(!nextLevel.count(tmp)) nextLevel.emplace(tmp);
                            }
                        }
                    }
                    tmp[i] = old;
                }
            }

            // 找到了路径
            if(flag) return true;
            else
            {
                curLevel.swap(nextLevel);
                nextLevel.clear();
            }
        }
        return false;
    }

    // dfs 利用 bfs 形成的反图去生成路径
    void dfs(string& word, string& target)
    {
        path.emplace_front(word);
        if(word == target)
        {
            ret.emplace_back(vector<string>(path.begin(), path.end()));
        }

        for(auto& next : g[word])
        {
            dfs(next, target);
        }
        // 回溯
        path.pop_front();
    }

public:
    vector<vector<string>> findLadders(string beginWord, string endWord, vector<string>& wordList) 
    {
        dict = unordered_set<string>(wordList.begin(), wordList.end());
        if(!dict.count(endWord)) return {};

        if(bfs(beginWord, endWord)) dfs(endWord, beginWord);
        return ret;
    }
};

// LCR 113. 课程表 II
class Solution 
{
public:
    vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) 
    {
        vector<vector<int>> g(numCourses);
        vector<int> ingree(numCourses);
        for(auto& e : prerequisites)
        {
            int x = e[0], y = e[1];
            g[y].push_back(x);
            ++ingree[x];
        } 

        queue<int> q;
        for(int i = 0; i < numCourses; ++i) if(!ingree[i]) q.push(i);

        vector<int> ret;
        while(!q.empty())
        {
            auto x = q.front();
            q.pop();
            ret.push_back(x);
            for(int y : g[x])
            {
                if(--ingree[y] == 0) q.push(y);
            }
        }
        
        if(ret.size() != numCourses) return {};
        return ret;
    }
};

// 牛客网拓扑排序模板题：链式前向星建图以及遍历
#include <iostream>
#include <vector>
#include <queue>
using namespace std;

const int MAXN = 200001; // 点的最大数量
const int MAXM = 200001; // 边的最大数量
int n; // 点的数量
int m; // 边的数量
int cnt = 1; // 边号
vector<int> Head(MAXN);
vector<int> Next(MAXM);
vector<int> To(MAXM);
vector<int> indegee(MAXN);
vector<int> ret; // 收集拓扑排序的结果

void addEdge(int f, int t)
{
    Next[cnt] = Head[f];
    To[cnt] = t;
    Head[f] = cnt++; 
}

bool topoSort()
{
    queue<int> q;
    for(int i = 1; i <= n; ++i) if(!indegee[i]) q.push(i);
    while(!q.empty())
    {
        int x = q.front();
        q.pop();
        ret.push_back(x);
        for(int ei = Head[x]; ei != 0; ei = Next[ei])
        {
            if(--indegee[To[ei]] == 0)
            {
                q.push(To[ei]);
            }
        }
    }
    return ret.size() == n;
}

int main() 
{   
    cin >> n >> m;
    for(int i = 0; i < m; ++i)
    {
        int from, to;
        cin >> from >> to;
        addEdge(from, to);
        ++indegee[to];
    }
    if(!topoSort())
    {
        cout << "-1" << endl;
    }
    else
    {
        for(int i = 0; i < n - 1; ++i)
        {
            cout << ret[i] << " ";
        }
        cout << ret[n - 1] << endl;
    }
    return 0;
}

//////////////////////////////////////////////////////////////
    // 分割线
/////////////////////////////////////////////////////////////

// 洛谷：拓扑排序模板题 https://www.luogu.com.cn/record/129364540
// 字典序最小的拓扑排序：借助小根堆
#include <iostream>
#include <vector>
#include <queue>

using namespace std;

int MAXN = 100001; // 点的最大数量
int MAXM = 100001; // 边的最大数量
int n, m;
int cnt = 1;
vector<int> head(MAXN);
vector<int> Next(MAXM);
vector<int> to(MAXM);
vector<int> indegree(MAXN);
vector<int> ret;

void addEdge(int u, int v)
{
    Next[cnt] = head[u];
    to[cnt] = v;
    head[u] = cnt++;
}

void topoSort()
{
    priority_queue<int, vector<int>, greater<int>> q;
    for(int i = 1; i <= n; ++i)
    {
        if(!indegree[i]) q.push(i);
    }
    
    while(!q.empty())
    {
        int x = q.top();
        q.pop();
        ret.push_back(x);
        for(int ei = head[x]; ei; ei = Next[ei])
        {
            if(--indegree[to[ei]] == 0)
            {
                q.push(to[ei]);
            }
        }
    }
}

int main()
{
    cin >> n >> m;
    for(int i = 0; i < m; ++i)
    {
        int from, to;
        cin >> from >> to;
        addEdge(from, to);
        ++indegree[to];
    }
    
    topoSort();
    for(int i = 0; i < n - 1; ++i)
    {
        cout << ret[i] << " ";
    }
    cout << ret[n - 1] << endl;
    
    return 0;
}

class Solution 
{
public:
    vector<int> lastVisitedIntegers(vector<string>& words) 
    {
        int m = words.size();
        int prevCount = 0, cnt = 0;
        vector<int> ret;
        vector<int> nums;
        for(auto& s : words)
        {
            if(s == "prev")
            {
                ++prevCount;
                if(cnt - prevCount >= 0)
                {
                    ret.push_back(nums[cnt - prevCount]);
                }
                else
                {
                    ret.push_back(-1);
                }
            }
            else
            {
                ++cnt;
                prevCount = 0;
                nums.push_back(stoi(s));
            }
        }    
        return ret;
    }
};

class Solution 
{
public:
    vector<string> getWordsInLongestSubsequence(int n, vector<string>& words, vector<int>& groups) 
    {
        vector<string> ret;
        int prev = -1;
        for(int i = 0; i < n; ++i)
        {
            if(groups[i] != prev)
            {
                ret.push_back(words[i]);
                prev = groups[i];
            }
        }    
        return ret;
    }
};